package jwtutil

import (
	"errors"
	"github.com/gin-gonic/gin"
	"shop/config/constant"
	"shop/utils/convertutil"
	"time"

	"github.com/cihub/seelog"
	"github.com/dgrijalva/jwt-go"
)

const (
	constSecretKey = "chenyaru_~!@#$%^&*()_+"
)

// JwtClaims 自定义Claims
type JwtClaims struct {
	UserId    int64
	ShopId    int
	CreateAt  int64
	ExpiresAt int64 // 过期时间
}

func (this *JwtClaims) Valid() error {
	now := time.Now().UnixNano() / 1000_000
	if now < this.CreateAt {
		return errors.New("当前时间小于创建时间")
	}
	if now >= this.ExpiresAt {
		return errors.New("已经过期")
	}
	return nil
}

// Refresh 续期
func (this *JwtClaims) Refresh(c *gin.Context) {
	now := time.Now().UnixNano() / 1000_000
	ttl := this.ExpiresAt - this.CreateAt
	if (this.ExpiresAt - now) <= ttl/2 { // 还剩少于一半时间过期时就进行续期
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, this)
		tokenStr, _ := token.SignedString([]byte(constSecretKey))
		if tokenStr != "" {
			seelog.Infof("token自动续期成功, jwtClaims: %v", convertutil.ToJsonString(this))
			c.Header(constant.ParamToken, tokenStr)
		}
	}
}

// GenToken expireAt = nowTime + ttl (unit:seconds)
func GenToken(claims *JwtClaims, ttl int64) string {
	now := time.Now().UnixNano() / 1000_000
	claims.CreateAt = now
	claims.ExpiresAt = now + ttl*1000
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenStr, _ := token.SignedString([]byte(constSecretKey))
	return tokenStr
}

func ParseToken(tokenStr string) (*JwtClaims, bool) {
	claims := &JwtClaims{}
	token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
		return []byte(constSecretKey), nil
	})
	if err != nil {
		seelog.Error("failed to parseToken, err: ", err)
		return claims, false
	}

	claims, ok := token.Claims.(*JwtClaims)
	if ok && token.Valid {
		return claims, true
	}
	return claims, false
}
